package com.jacksay.vikingfl.autocompletermulti
{
	import com.jacksay.vikingfl.autocompleter.AutoCompleterRemoteCompletionRenderer;
	import com.jacksay.vikingfl.autocompleter.AutoCompleterRemoteError;
	import com.jacksay.vikingfl.autocompleter.AutoCompleterRemoteEvent;
	import com.jacksay.vikingfl.stringtools.StringTools;
	import com.jacksay.vikingfl.textinput.PromptTextInputEvent;
	
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ICollectionView;
	import mx.collections.Sort;
	import mx.containers.HBox;
	import mx.controls.List;
	import mx.core.ClassFactory;
	import mx.core.UITextField;
	import mx.events.FlexEvent;
	import mx.events.ListEvent;
	import mx.managers.PopUpManager;
	import mx.utils.ArrayUtil;
	import mx.utils.ObjectUtil;
	
	[Event(name="selectedItemChange", type="com.jacksay.vikingfl.autocompleter.AutoCompleterRemoteEvent")]
	[Event(name="textChange", type="com.jacksay.vikingfl.textinput.PromptTextInputEvent")]
	
	[DefaultProperty("fields")]
	public class AutoCompleterRemoteMulti extends HBox
	{
		// ---------------------------------------------------------------------
		//
		// PRIVATE PROPERTY
		//
		// ---------------------------------------------------------------------
		/**
		 * Contiend une référence au champ actif courant
		 * 
		 * author jacksay14
		 */
		private var field_active:AutoCompleterRemoteMultiField = null;
		
		
		
		/**
		 * Utilisé pour éviter de perdre le selectedItem lors du textChange
		 * 
		 * @author jacksay14
		 */
		private var fSelectedItemInProgress:Boolean = false;
		
		
		
		// ---------------------------------------------------------------------
		//
		// PROTECTED PROPERTY
		//
		// ---------------------------------------------------------------------
		/**
		 * Completion
		 */
		protected var completion:List = new List();
		
		
		
		// ---------------------------------------------------------------------
		//
		// PUBLIC
		//
		// ---------------------------------------------------------------------
		
		// ---------------------------------------------------------------------
		// fields
		// ---------------------------------------------------------------------
		/**
		 * Array<AutoCompleterRemoteMultiField>, liste des champs affichées pour
		 * la completion.
		 *
		 * @author jacksay14 
		 */
		[ArrayElementType("com.jacksay.vikingfl.autocompletermulti.AutoCompleterRemoteMultiField")]
		public function get fields() :Array {
			return _fields;
		}
		
		/**
		 * @private
		 */
		private var _fields:Array = null;
		
		
		/**
		 * @private 
		 */
		public function set fields( value:Array ) :void {
			_fields = value;
		}
		
		
		
		// ---------------------------------------------------------------------
		// completionPattern
		// ---------------------------------------------------------------------
		/**
		 * Chaine décrivant la manière de rendre la donnée dans la completion. 
		 * le pattern se présente sous la forme %property1 %propertyN. ou
		 * 'propertyN' correspond à une propriété des objets manipulés.
		 * 
		 * @exemple <p>L'objet suivant :</p> 
		 * <code>
		 * var obj:Object{ nom:"Beckett", prenom:"Samuel" }
		 * </code>
		 * <p>Peut être formatté sous la forme nom prenom via un pattern 
		 * <code>%nom %prenom</code>
		 * 
		 * @type String
		 * @author jacksay14
		 */
		[Inspectable(type="String", defaultValue=null)]
		public function get completionPattern() :String {
			return _completionPattern;
		}
		
		/**
		 * @private
		 */
		private var _completionPattern:String = null;
		
		/**
		 * @private
		 */
		public function set completionPattern( value:String ) :void {
			_completionPattern = value;
		}
		
		// ---------------------------------------------------------------------
		// data
		// ---------------------------------------------------------------------
		override public function set data(value:Object):void {
			selectedID = int(value);
			
		}
		
		[Bindable]
		override public function get data() :Object {
			return selectedID;
		}
		
		// ---------------------------------------------------------------------
		// selectedItem
		// ---------------------------------------------------------------------
		/**
		 * Item présent daans la completion en cours de selection
		 * 
		 * @author jacksay14
		 */
		[Bindable("selectedItemChange")]
		public function get selectedItem() :* {
			return _selectedItem;
		}
		
		/**
		 * @private
		 */
		private var _selectedItem:* = null;
		
		/**
		 * @private
		 */
		public function set selectedItem( value:* ) :void {
			
			if( value != _selectedItem ){
				var field:AutoCompleterRemoteMultiField;
				fSelectedItemInProgress = true;
				
				if( value == null ){
					_selectedItem = null;
					_selectedID = -1;
					for each( field in fields ){
						field.hasSelectedItem = false;
					}
					fSelectedItemInProgress = false;
					dispatchEvent(new AutoCompleterRemoteEvent(AutoCompleterRemoteEvent.SELECT_ITEM_CHANGE));
					dispatchEvent(new PromptTextInputEvent(PromptTextInputEvent.TEXT_CHANGE));
					return;
				}
				var dt:Array = completionAC.source;
				for each( var item:* in dt ){
					if( item == value ){
						_selectedItem = item;
						_selectedID = item[idName];
						for each( field in fields ){
							field.text = item[field.propertyName];
							field.hasSelectedItem = true;
						}
						fSelectedItemInProgress = false;
						dispatchEvent(new AutoCompleterRemoteEvent(AutoCompleterRemoteEvent.SELECT_ITEM_CHANGE));
						dispatchEvent(new PromptTextInputEvent(PromptTextInputEvent.TEXT_CHANGE));
						return;
					}
				}
			}
		}
		
		
		
		// ---------------------------------------------------------------------
		// selectedID
		// ---------------------------------------------------------------------
		/**
		 * Clef primaire de la donnée manipulée, elle DOIT être un entier unique
		 * 
		 * @type int
		 * 
		 * @author jacksay14
		 */
		[Bindable("selectedItemChange")]
		public function get selectedID() :int {
			return _selectedID;
		}
		
		/**
		 * @private
		 */
		private var _selectedID:int = -1;
		
		/**
		 * @private
		 */
		public function set selectedID( value:int ) :void {
			// if( value < 1 ) text = "";
			if( value != _selectedID ) {
				
				if( value == -1 ){
					selectedItem = null;
					return;
				} 
				
				var dt:Array = completionAC.source;
				for each( var item:* in dt ){
					if( item[idName] == value ){
						selectedItem = item;
						return;
					}
				}
					
				if( fRealTimeMode ){
					remoteGetItemById( value );
				} else {
					selectedItem == null;
				}
			}
		}
		
		
		
		// ---------------------------------------------------------------------
		// idName
		// ---------------------------------------------------------------------
		/**
		 * Nom de la propriété qui contiend la clef primaire des les objets du
		 * dataProvider.
		 * 
		 * @defaultValue "id"
		 * @type String
		 * 
		 * @author jacksay14
		 */
		public function get idName() :String {
			return _idName;
		}
		
		/**
		 * @private
		 */
		private var _idName:String = "id";
		
		/**
		 * @private
		 */
		public function set idName( value:String ) :void {
			_idName = value;
		}
		
		
		
		
		// ---------------------------------------------------------------------
		//
		// PUBLIC PROPERTIES : completion
		//
		// ---------------------------------------------------------------------
		
		// ---------------------------------------------------------------------
		// dataProvider
		// ---------------------------------------------------------------------
		public function get dataProvider() :Object {
			return completion.dataProvider;
		}
		
		public function set dataProvider( value:Object ) :void {
			completion.dataProvider = value;
			ICollectionView(completion.dataProvider).filterFunction = completionFilter;
		}
		
		
		
		// ---------------------------------------------------------------------
		// completionRows
		// ---------------------------------------------------------------------
		/**
		 * Nombre de lignes maximum affichées dans la completion
		 * 
		 * @default 5
		 */
		public function get completionRows() :Number {
			return _completionRows;
		}
		
		private var _completionRows:Number = 5;
		
		public function set completionRows( value:Number ) :void {
			_completionRows = value;
		}
		
		
		
		// ---------------------------------------------------------------------
		// completionLabelFunction
		// ---------------------------------------------------------------------
		/**
		 * Mise en forme dans l'autocompleter
		 * 
		 * @default null
		 * @deprecated
		 */
		[Deprecated(
			message="Préférer l'utilisation de la propriété completionPattern afin de bénéficier de la mise en gras de la recherche dans la completion", 
			replacement="completionPattern"
		)] 
		public function get completionLabelFunction() :Function {
			return _completionLabelFunction;
		}
		
		private var _completionLabelFunction:Function = null;
		
		public function set completionLabelFunction( value:Function ) :void {
			_completionLabelFunction = value;
		}
		
		
		
		// ---------------------------------------------------------------------
		// completionStartAt
		// ---------------------------------------------------------------------
		/**
		 * Détermine les conditions d'ouverture de la completion
		 * 
		 * @default 2
		 */
		public function get completionStartAt() :int {
			return _completionStartAt;
		}
		
		/**
		 * @private
		 */
		private var _completionStartAt:int = 2;
		
		/**
		 * @private
		 */
		public function set completionStartAt( value:int ) :void {
			_completionStartAt = value;
		}
		
		
		
		// ---------------------------------------------------------------------
		//
		// SHORTCUT FUNCTION
		//
		// ---------------------------------------------------------------------
		protected function get completionAC() :ArrayCollection {
			return ArrayCollection(completion.dataProvider);
		}
		
		
		
		public function AutoCompleterRemoteMulti()
		{
			super();
			height = 20;
			clipContent = false;
			if( dataProvider == null ) dataProvider = new ArrayCollection();
			addEventListener(FlexEvent.CREATION_COMPLETE, configureListener, false, 0, true);
		}
		
		protected function configureListener( e:Event=null ) :void {
			completion.addEventListener(ListEvent.ITEM_CLICK, completionSelectActive, false, 0, true)
			
		}
		
		override protected function initializationComplete():void {
			super.initializationComplete();
		}
		
		// ---------------------------------------------------------------------
		//
		// PROTECTED FUNCTIONS : completion
		//
		// ---------------------------------------------------------------------
		
		// Cette propriété permet de savoir si l'autocompleter doit être montré
		private var fCompletionShowable:Boolean = false;
		
		protected function completionDisplay() :void {
			
			if( !canComplete() ) {
				completionHide();
				return;
			}
			
			var perf:int = getTimer();
			var sort:Sort = new Sort();
			sort.fields = [field_active.sorter];
			completionAC.sort = sort;
			completionAC.refresh();
			
			
			if( completionAC.length > 0 ){
				
				if( !completion.visible ){
					trace("+ Completion ON");
					PopUpManager.addPopUp(completion, this);
					completion.visible = true;
					
					completion.width = width;
					var p:Point = new Point(x, y);
					var gp:Point = localToGlobal(p);
					completion.x = gp.x - x;
					completion.y = gp.y - y + height;
				}
				
				if( completionAC.length > completionRows ){
					completion.rowCount = completionRows;
				} else {
					completion.rowCount = completionAC.length;
				}
				
				
			} else {
				completionHide();
			}
		}
		
		
		/**
		 * Evalue les recherche des champs pour savoir si la requète doit être 
		 * executée.
		 * 
		 * @return Boolean
		 * @author jacksay14
		 */
		protected function canRequest() :Boolean {
			var field:AutoCompleterRemoteMultiField;
			for each( field in fields ){
				if( field.text.length == field.searchStartAt ) return true;
			}
			return false;
		}
		
		
		/**
		 * Evalue les recherche des champs pour savoir si la completion peut 
		 * être affichée.
		 * 
		 * @return Boolean
		 * @author jacksay14
		 */
		protected function canComplete() :Boolean {
			if( !fRealTimeMode ) return true;
			var field:AutoCompleterRemoteMultiField;
			for each( field in fields ){
				if( field.text.length >= field.searchStartAt ) return true;
			}
			
			return false;
		}
		
		
		
		
		protected function completionHide() :void {
			if( completion != null && completion.visible == true ){
				trace("+ Completion OFF");
				completion.visible = false;
				PopUpManager.removePopUp(completion);
			}
		}
		
		protected function completionFilter( o:Object ) :Boolean {
			
			for each( var field:AutoCompleterRemoteMultiField in fields ){
				if( field.filterData(o) == false ) return false;
			}
			
			return true;
		}
		
		
		
		/**
		 * Selectionne l'item actif dans la completion
		 * 
		 * @parm e Event peut être null
		 * @return void
		 * @author jacksay14
		 */
		protected function completionSelectActive( e:Event=null ) :void {
			if( completion.selectedIndex > -1 ){
				selectedItem = completion.selectedItem;
				field_active.setSelection(field_active.length, field_active.length);
				completionHide();
			}
		}
		
		
		
		/**
		 * Donne le focus au champ suivant
		 * 
		 * @return void
		 * @author jacksay14
		 */
		protected function fieldFocusNext() :void {
			var field:AutoCompleterRemoteMultiField = getNextField();
			if( field != null ){ 
				field.setFocus();
				field.setSelection(field.text.length, field.text.length);
			}
		}
		
		
		
		/**
		 * Donne le focus au champ précédent
		 * 
		 * @return void
		 * @author jacksay14
		 */
		protected function fieldFocusPrev() :void {
			var field:AutoCompleterRemoteMultiField = getPrevField();
			if( field != null ){ 
				field.setFocus();
				field.setSelection(field.text.length, field.text.length);
			}
		}
		
		
		
		/**
		 * Retourne la champ précédent
		 * 
		 * @return AutoCompleterRemoteMultiField ou null
		 * @author jacksay14
		 */
		protected function getPrevField() :AutoCompleterRemoteMultiField {
			if( field_active == null ) return fields[0];
			
			var index:int = ArrayUtil.getItemIndex(field_active, fields);
			if( index > 0 ){
				var field:AutoCompleterRemoteMultiField = AutoCompleterRemoteMultiField(fields[--index]); 
				return field;
			}
			return null;
		}
		
		
		
		/**
		 * Retourne la champ suivant
		 * 
		 * @return AutoCompleterRemoteMultiField ou null
		 * @author jacksay14
		 */
		protected function getNextField() :AutoCompleterRemoteMultiField {
			if( field_active == null ) return fields[0];
			
			var index:int = ArrayUtil.getItemIndex(field_active, fields);
			if( index < fields.length-1 ){
				var field:AutoCompleterRemoteMultiField = AutoCompleterRemoteMultiField(fields[++index]); 
				return field;
			}
			return null;
		}
		
		
		
		// ---------------------------------------------------------------------
		//
		// PROTECTED FUNCTIONS
		//
		// ---------------------------------------------------------------------
		
		/**
		 * Cré les champs de l'AutoCompleterRemoteMulti. Et renseigne le pattern
		 * de completion si sa valeur est NULL;
		 * 
		 * @return void
		 * 
		 * @author jacksay14
		 * @since 2009-12-10
		 */
		protected function fieldsCreate() :void {
			var defaultPattern:String = "";
			var sep:String = "%";
			for each( var field:AutoCompleterRemoteMultiField in _fields ){
				fieldsConfigureListener(field);
				addChild(field);
				defaultPattern = defaultPattern.concat(sep,field.propertyName);
				sep = " %";
			}
			if( completionPattern == null ) completionPattern = defaultPattern;
		}
		
		
		
		/**
		 * Ajoute les écouteurs sur les AutoCompleterMultiField créé via la 
		 * fonction <code>fieldsCreate()</code>
		 * 
		 * @param field AutoCompleterRemoteMultiField
		 * @return void
		 * 
		 * @author jacksay
		 */
		protected function fieldsConfigureListener( field:AutoCompleterRemoteMultiField ) :void {
			field.addEventListener(PromptTextInputEvent.TEXT_CHANGE, handlerFieldChange, false, 0, true);
			field.addEventListener(KeyboardEvent.KEY_UP, handlerFieldKeyUp, false, 0, true);
			field.addEventListener(KeyboardEvent.KEY_DOWN, handlerFieldKeyDown, false, 0, true);
			field.addEventListener(FocusEvent.FOCUS_OUT, handlerFocusOut, false, 0, true);
		}
		
		/**
		 * Supprime les écouteurs d'un AutoCompleterMultiField.
		 * 
		 * @param field AutoCompleterRemoteMultiField
		 * @return void
		 * 
		 * @author jacksay
		 *
		protected function fieldsRemoveListener( field:AutoCompleterRemoteMultiField ) :void {
			field.removeEventListener(PromptTextInputEvent.TEXT_CHANGE, handlerFieldChange);
			field.removeEventListener(KeyboardEvent.KEY_UP, handlerFieldKeyUp);
			field.removeEventListener(KeyboardEvent.KEY_DOWN, handlerFieldKeyDown);
			field.removeEventListener(FocusEvent.FOCUS_OUT, handlerFocusOut);
		}
		/****/
		
		
		
		
		/**
		 * Laisse la completion ouverte si le composant de destination est un 
		 * AutoCompleterMultiField contenu dans fields.
		 * 
		 * @return void
		 * @author jacksay14
		 */
		protected function handlerFocusOut( e:FocusEvent ) :void {
			// 
			try {
				var destination:AutoCompleterRemoteMultiField = AutoCompleterRemoteMultiField(UITextField(e.relatedObject).owner);
				if( ArrayUtil.getItemIndex(destination, fields) < 0 ){
					completionHide();
				}
			} catch( e:Error ) {
				completionHide();
			}
		}
		
		
		
		/** 
		 * Capture des touches du clavir ENFONCE
		 */
		protected function handlerFieldKeyDown( e:KeyboardEvent ) :void {
			field_active = AutoCompleterRemoteMultiField(e.currentTarget);
			
			// RIGHT : Déplace le focus vers le champ précédent si la position 
			// du curseur est à la fin de la chaine dans le champ actif
			if( e.keyCode == Keyboard.RIGHT ){
				if	( field_active.text.length == field_active.selectionBeginIndex && field_active.selectionBeginIndex == field_active.selectionEndIndex ){
					fieldFocusNext();
				}
			} 
			// LEFT : Déplace le focus vers le champ suivant si la position du 
			// curseur est au début de la chaine dans le champ actif
			else if( e.keyCode == Keyboard.LEFT ){
				if( field_active.selectionBeginIndex == 0 && field_active.selectionEndIndex == 0 ){
					fieldFocusPrev();
				}
			}
			// BACKSPACE : Déplace le focus vers le champ précédent si la 
			// position du curseur est à 0 dans le champ actif
			else if ( e.keyCode == Keyboard.BACKSPACE ){
				if( field_active.selectionBeginIndex == 0 && field_active.selectionEndIndex == 0 ){
					callLater(fieldFocusPrev);
				}
			}
			
			// DELETE : si le contenu
			else if ( e.keyCode == Keyboard.DELETE ){
				if( field_active.selectionBeginIndex == field_active.text.length && field_active.selectionEndIndex == field_active.text.length ){
					var next:AutoCompleterRemoteMultiField = getNextField();
					if( next != null ){
						next.text = next.text.substr(1);
					}
				}
			}
		}
		
		protected function handlerFieldKeyUp( e:KeyboardEvent ) :void {
			field_active = AutoCompleterRemoteMultiField(e.currentTarget);
			
			// ESCAPE : Cache la completion
			if( e.keyCode == Keyboard.ESCAPE ){
				handlerKeyUpEscape(e);
			} 
			
			// DOWN : Selectionne l'item suivant
			else if ( e.keyCode == Keyboard.DOWN ) {
				handlerKeyUpDown(e);
			} 
			
			// UP : Selectionne l'item précédent si possible
			else if ( e.keyCode == Keyboard.UP ) {
				handlerKeyUpUp(e);
			} 
			
			// ENTER : Validation
			else if ( e.keyCode == Keyboard.ENTER ) {
				completionSelectActive();
			}
		}
		
		protected function handlerKeyUpDown( e:KeyboardEvent ) :void {
			if( !completion.visible ){
				completionDisplay();
			} else {
				if( completion.selectedIndex < completionAC.length ){
					completion.selectedIndex++;
					completion.scrollToIndex(completion.selectedIndex);
				}
			}
		}
		
		protected function handlerKeyUpUp( e:KeyboardEvent ) :void {
			if( completion.visible && completion.selectedIndex > 0 ){
				completion.selectedIndex--;
				completion.scrollToIndex(completion.selectedIndex);
			}
		}
		
		protected function handlerKeyUpEscape( e:KeyboardEvent ) :void {
			completionHide();
		}
		
		/**
		 * Déclenché lorsque la saisie change dans le champ tramsis en 
		 * target.
		 * 
		 * @param e PromptTextInputEvent
		 * @author jacksay14
		 */
		protected function handlerFieldChange( e:PromptTextInputEvent ) :void {
			
			field_active = AutoCompleterRemoteMultiField(e.currentTarget);
			
			// Si un selected item est en cours d'affectation
			// on ne fait rien pour éviter le reset du selectedItem
			if( fSelectedItemInProgress ) return;
			
			
			// On test un potentiel changement
			if( selectedItem != null && field_active.text != selectedItem[field_active.propertyName] ){
				selectedItem = null;
			}
			
			// MODE CONNECTE
			if( fRealTimeMode ){
				
				// Si un item est selectionné ou si le nombre de caractère
				// est insufisant, on cache la completion
				if( selectedItem != null ){
					completionHide(); 
					return;
				}
				
				// Envois de requète
				if( canRequest() ){
					remoteGetItemList();
				}
				
				else {
					completionDisplay()
				}
				dispatchEvent(new PromptTextInputEvent(PromptTextInputEvent.TEXT_CHANGE));
			}
			
			// MODE DECONNECTE
			else {
				if( selectedItem == null ){
					completionDisplay();
				}
				dispatchEvent(new PromptTextInputEvent(PromptTextInputEvent.TEXT_CHANGE));
			}
		}
		// ---------------------------------------------------------------------
		//
		// PROTECTED DATA FORMAT
		//
		// ---------------------------------------------------------------------
		protected function formatCompletionWithBoldMatch( o:Object ) :String {
			// var texte:String = ( completionLabelFunction == null )?defaultCompletionLabelFunction(o):completionLabelFunction(o);
			return defaultCompletionLabelFunction(o);
		}
		
		protected function defaultCompletionLabelFunction( o:Object ) :String {
			// return StringTools.renderObjectWithPattern(o, "%nom %nom");
			var toFormat:Object = ObjectUtil.copy(o);
			var field:AutoCompleterRemoteMultiField;
			var propertyName:String;
			var prefix:String = '<i>';
			var suffix:String = '</i>';
			
			for each( field in fields ){
				propertyName = field.propertyName;
				if( field_active == field ){
					prefix = '<b><u>';
					suffix = '</u></b>';
				} else {
					prefix = '<b>';
					suffix = '</b>';
				}
				toFormat[propertyName] = StringTools.renderStringMatch(o[propertyName], field.text, field.searchSensitiveCase,prefix, suffix);
			}
			return StringTools.renderObjectWithPattern(toFormat, completionPattern);
		}
		
		
		// ---------------------------------------------------------------------
		//
		// PROTECTED REMOTE FUNCTION
		//
		// ---------------------------------------------------------------------
		protected var fRealTimeMode:Boolean = false;
		
		/**
		 * <b>Méthode à surcharger</b> pour lancer la requète de 
		 * récupération des listes.
		 * 
		 * @author jacksay14
		 */
		protected function remoteGetItemList() :void {
			throw new AutoCompleterRemoteError(AutoCompleterRemoteError.REMOTE_CALL_LISTE_FUNCTION_UNDEFINED);
		}



		/**
		 * Méthode à executer lors de la récupération des données
		 * 
		 * @author jacksay14
		 */
		protected function remoteGetItemListResult( value:Array ) :void {
			dataProvider = new ArrayCollection(value);
			completionDisplay();
		}


		
		/**
		 * <b>Méthode à surcharger</b> pour lancer la requète de récupération 
		 * par ID.
		 * 
		 * @author jacksay14
		 */
		protected function remoteGetItemById( value:int ) :void {
			throw new AutoCompleterRemoteError(AutoCompleterRemoteError.REMOTE_CALL_ITEM_BY_ID_FUNCTION_UNDEFINED);
		}
		
		
		
		/**
		 * Méthode à executer lors de la récupération de la donnée par ID
		 * 
		 * @author jacksay14
		 */
		protected function remoteGetItemByIdResult( item:* ) :void {
			// La donnée semble absente de la base de donnée
			if( item == null ){
				selectedItem = null;
			}
			
			// On push l'item obtenu dans le dataProvider
			else 
			{
				ArrayCollection(dataProvider).addItem(item);
				selectedItem = item;
			}
		}
		
		
		
		override protected function createChildren():void {
			super.createChildren();
			
			// field
			fieldsCreate();
			
			// Completion
			completion.focusEnabled = false;
			completion.visible = false;
			completion.labelFunction = formatCompletionWithBoldMatch;
			completion.itemRenderer = new ClassFactory( AutoCompleterRemoteCompletionRenderer );
			// PopUpManager.addPopUp(completion, this);
		}
		
		override protected function measure():void {
			super.measure();
			measuredWidth	 	= 150;
			measuredMinWidth 	= 150;
			measuredHeight		= 20;
			measuredMinHeight	= 20;
		}
	}
}